package com.smart.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.smart.common.PageInfo;
import com.smart.common.enums.OperateTypeEnum;
import com.smart.common.enums.ProjectConstructionStatusEnum;
import com.smart.common.enums.ReportTypeEnum;
import com.smart.common.enums.SuperviseModuleEnum;
import com.smart.common.service.LogService;
import com.smart.common.utils.AssertUtil;
import com.smart.context.SessionContext;
import com.smart.mapper.ProjectReportMapper;
import com.smart.mapper.ProjectWeeklyItemMapper;
import com.smart.mapper.ProjectWeeklyTaskMapper;
import com.smart.model.convert.ProjectItemConvert;
import com.smart.model.convert.ProjectReportConvert;
import com.smart.model.domain.ProjectItemDO;
import com.smart.model.domain.ProjectReportDO;
import com.smart.model.domain.ProjectWeeklyItemDO;
import com.smart.model.domain.ProjectWeeklyTaskDO;
import com.smart.model.dtomapper.ProjectReportDtoMapper;
import com.smart.model.request.ProjectReportRequest;
import com.smart.model.util.ProjectWeeklyItemConvert;
import com.smart.model.vo.ProjectItemVO;
import com.smart.model.vo.ProjectReportVO;
import com.smart.model.vo.ProjectTempTaskVO;
import com.smart.model.vo.ProjectVO;
import com.smart.model.vo.ProjectWeeklyItemVO;
import com.smart.service.*;
import com.smart.utils.WeekUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author zhanghong
 */
@Slf4j
@Service
public class ProjectReportServiceImpl extends ServiceImpl<ProjectReportMapper, ProjectReportDO> implements ProjectReportService {
    @Autowired
    private ProjectReportMapper projectReportMapper;
    @Autowired
    private ProjectTempTaskService projectTempTaskService;
    @Autowired
    private ProjectItemService projectItemService;
    @Autowired
    private ProjectWeeklyItemMapper projectWeeklyItemMapper;
    @Autowired
    private ProjectService projectService;
    @Autowired
    private ProjectWeeklyTaskMapper projectWeeklyTaskMapper;
    @Autowired
    private LogService logService;

    @Override
    public ProjectReportVO getByKey(long id) {
        ProjectReportDO projectReportDO = getById(id);
        ProjectReportVO projectReportVO = ProjectReportDtoMapper.INSTANCE.do2VO(projectReportDO);
        fillInfo(projectReportVO);
        return projectReportVO;
    }
    @Override
    public PageInfo<ProjectReportVO> tempPageQuery(ProjectReportRequest request) {
        Long projectId = SessionContext.getProjectId();
        AssertUtil.assertNotNull(projectId, "当前接口为云服务平台查询接口");
        request.setProjectId(projectId);
        request.setItemType(ReportTypeEnum.TEMP.name());
        long count = projectReportMapper.tempPageCount(request);
        List<ProjectReportDO> list = projectReportMapper.tempPageQuery(request, request.getPageSize(), request.fetchOffSet());
        List<ProjectReportVO> projectReportVOList = ProjectReportConvert.buildProjectReportVoList(list);
        fillInfo(projectReportVOList);
        return new PageInfo(request.getPageNum(), request.getPageSize(), projectReportVOList, count);
    }
    @Override
    public PageInfo<ProjectReportVO> weeklyPageQuery(ProjectReportRequest request) {
        Long projectId = SessionContext.getProjectId();
        AssertUtil.assertNotNull(projectId, "当前接口为云服务平台查询接口");
        request.setProjectId(projectId);
        request.setItemType(ReportTypeEnum.WEEKLY.name());
        long count = projectReportMapper.weeklyPageCount(request);
        List<ProjectReportDO> list = projectReportMapper.weeklyPageQuery(request, request.getPageSize(), request.fetchOffSet());
        List<ProjectReportVO> projectReportVOList = ProjectReportConvert.buildProjectReportVoList(list);
        fillInfo(projectReportVOList);
        return new PageInfo(request.getPageNum(), request.getPageSize(), projectReportVOList, count);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByKey(ProjectReportRequest request) {
        //检验项目是否存在
        AssertUtil.assertNotNull(request.getProjectId(), "项目id不能为空");
        AssertUtil.assertNotNull(projectService.getById(request.getProjectId()), "项目不存在");
        AssertUtil.assertNotNull(request.getTaskId(), "任务id不能为空");
        if (Objects.equals(request.getItemType(), "WEEKLY")) {
            AssertUtil.assertNotNull(projectWeeklyTaskMapper.selectDOById(request.getTaskId()), "任务不存在");
        } else {
            AssertUtil.assertNotNull(projectTempTaskService.getById(request.getTaskId()), "任务不存在");
        }

        ProjectReportDO projectReportDO = ProjectReportDtoMapper.INSTANCE.request2DO(request);
        projectReportDO.setStatus(1);
        saveOrUpdate(projectReportDO);

        //记录操作日志
        String beforeContent = null;
        if (projectReportDO != null) {
            beforeContent = JSON.toJSONString(projectReportDO);
        }
        String afterContent = JSON.toJSONString(getById(projectReportDO.getId()));
        OperateTypeEnum operateType = projectReportDO == null ? OperateTypeEnum.新建 : OperateTypeEnum.修改;
        logService.logSupervisePlatform(SuperviseModuleEnum.临时任务, operateType, projectReportDO.getId(), beforeContent, afterContent);
        return true;
    }
    @Override
    public List<ProjectItemVO> queryReportItem(Long id) {
        ProjectReportDO projectReportDO = projectReportMapper.selectDOById(id);
        AssertUtil.assertNotNull(projectReportDO, "数据不存在");
        if (Objects.equals(projectReportDO.getItemType(), ReportTypeEnum.TEMP.name())) {
            AssertUtil.assertNotNull(projectReportDO.getTaskId(), "临时提报任务不存在");
            ProjectTempTaskVO taskVO = projectTempTaskService.getByKey(projectReportDO.getTaskId());
            AssertUtil.assertNotNull(taskVO, "临时提报任务不存在");
        }
        List<ProjectItemDO> itemDOS = projectItemService.lambdaQuery()
                .eq(ProjectItemDO::getTaskId, projectReportDO.getTaskId())
                .orderByAsc(ProjectItemDO::getSortNum)
                .list();
        if (CollectionUtils.isEmpty(itemDOS)) {
            return Collections.emptyList();
        }
        return ProjectItemConvert.buildProjectItemVoList(itemDOS);
    }

    @Override
    public List<ProjectWeeklyItemVO> queryWeeklyReportItem(Long id) {
        ProjectReportDO projectReportDO = projectReportMapper.selectDOById(id);
        AssertUtil.assertNotNull(projectReportDO, "数据不存在");
        AssertUtil.assertNotNull(projectReportDO.getTaskId(), "周报任务不存在");
        ProjectWeeklyTaskDO weeklyTaskDO = projectWeeklyTaskMapper.selectDOById(projectReportDO.getTaskId());
        AssertUtil.assertNotNull(weeklyTaskDO, "周报任务不存在");

        List<ProjectWeeklyItemDO> weeklyItemDOS = projectWeeklyItemMapper.queryWeeklyReportItemByWeeklyId(weeklyTaskDO.getId());
        return ProjectWeeklyItemConvert.buildProjectWeeklyItemVoList(weeklyItemDOS);
    }

    @Override
    public Boolean projectStatusChangeAdd(Long projectId, String projectStatus) {
        ProjectConstructionStatusEnum anEnum = ProjectConstructionStatusEnum.getEnum(projectStatus);
        AssertUtil.assertNotNull(anEnum, "当前工程状态非法");
        List<ProjectConstructionStatusEnum> targetStatusEnum = Lists.newArrayList(ProjectConstructionStatusEnum.RUNNING, ProjectConstructionStatusEnum.WAIT_ACCEPT);
        if (!targetStatusEnum.contains(anEnum)) {
            log.info("当前状态无需添加周报任务 {}", anEnum.name());
            return true;
        }

        ProjectVO byKey = projectService.getByKey(projectId);
        AssertUtil.assertNotNull(byKey, "项目不存在");

        //查询当周是否有周报任务
        Date date = new Date();
        int year = DateUtil.year(date);
        int week = DateUtil.weekOfYear(date);
        ProjectWeeklyTaskDO weeklyTaskDO = projectWeeklyTaskMapper.queryByYearAndWeek(year, week);
        if (weeklyTaskDO == null) {
            log.info("当周不存在提报任务");
            return true;
        }

        //是否已经存在周报任务实例
        ProjectReportDO reportDO = projectReportMapper.queryByProjectIdAndTaskId(projectId, weeklyTaskDO.getId());
        if (reportDO != null) {
            log.info("已经存在周报实例无需二次添加");
            return true;
        }

        //添加周报实例任务
        ProjectReportDO reportInstance = new ProjectReportDO();
        reportInstance.setTaskId(weeklyTaskDO.getId());
        reportInstance.setProjectId(projectId);
        reportInstance.setItemType(ReportTypeEnum.WEEKLY.name());
        save(reportInstance);
        return true;
    }

    @Override
    public List<ProjectReportVO> listQuery(ProjectReportRequest request) {
        List<ProjectReportDO> list = list();
        List<ProjectReportVO> projectReportVOS = ProjectReportConvert.buildProjectReportVoList(list);
        return projectReportVOS;
    }

    @Override
    public Boolean add(ProjectReportRequest request) {
        ProjectReportDO projectReportDO = ProjectReportDtoMapper.INSTANCE.request2DO(request);
        save(projectReportDO);
        return true;
    }

    @Override
    public Boolean deleteByKey(long id) {
        projectReportMapper.deleteDOById(id);
        return true;
    }

    /**
     * 生成周报任务
     * @param projectId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createWeeklyTask(Long projectId) {
        Date date = new Date();
        int weekNum = WeekUtil.getWeekNum();
        int yearNum = DateUtil.year(date);
        ProjectWeeklyTaskDO weeklyTaskDO = projectWeeklyTaskMapper.queryByYearAndWeek(yearNum, weekNum);
        if (weeklyTaskDO == null) {
            log.info("当周任务不存在...");
            return true;
        }

        //为项目生成周报任务
        ProjectReportDO reportDO = new ProjectReportDO();
        reportDO.setProjectId(projectId);
        reportDO.setTaskId(weeklyTaskDO.getId());
        reportDO.setItemType(ReportTypeEnum.WEEKLY.name());
        boolean exists = this.lambdaQuery().eq(ProjectReportDO::getTaskId, reportDO.getTaskId()).eq(ProjectReportDO::getProjectId, reportDO.getProjectId()).exists();
        if (!exists) {
            this.save(reportDO);
        }
        return true;
    }

    private void fillInfo(List<ProjectReportVO> projectReportVOList) {
        for (ProjectReportVO vo : projectReportVOList) {
            fillInfo(vo);
        }
    }

    private void fillInfo(ProjectReportVO projectReportVO) {
        ProjectTempTaskVO byKey = projectTempTaskService.getByKey(projectReportVO.getTaskId());
        if (byKey != null) {
            projectReportVO.setTaskName(byKey.getName());
            projectReportVO.setTaskNum(byKey.getTaskNum());
            projectReportVO.setDeadlineDate(byKey.getEndTime());
        }
        ProjectWeeklyTaskDO projectWeeklyTaskDO = projectWeeklyTaskMapper.selectDOById(projectReportVO.getTaskId());
        if (projectWeeklyTaskDO != null) {
            projectReportVO.setYear(projectWeeklyTaskDO.getYear());
            projectReportVO.setWeek(projectWeeklyTaskDO.getWeekNum());
            projectReportVO.setStartTime(projectWeeklyTaskDO.getStartTime());
            projectReportVO.setEndTime(projectWeeklyTaskDO.getEndTime());
        }
    }
}
